/*	Scout class definition.
 *
*/

#include "Scout.h"

// scout every minute or so
static const int ScoutingInterval = 24*60;

Scout::Scout(std::string incName) : Behavior(incName),
									designatedScout(NULL),
									lastScoutFrame(-1)
{
	currentBaseScouting = 0;
	isInitYet = false;
}

void Scout::Enter()
{
	DEBUG_PRINT("Scout(%p) entering.\n", this);

	if(!isInitYet)
	{
		initPaths();
	}
}

void Scout::Execute()
{
	DEBUG_PRINT("Scout(%p) executing.\n", this);
	std::list<Base*>* bases = BB->GetBases();
	std::list<BWAPI::Unit*>* scvs = bases->front()->GetUnitsByType(BWAPI::UnitTypes::Terran_SCV);
	std::list<BWAPI::Unit*>* vultures = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Vulture);



	DEBUG_PRINT("Grabbing worker list scvs(%p) of size %d.\n", scvs, scvs->size());
	
	bool shouldIncr = false;
	if(designatedScout && !designatedScout->exists())
		shouldIncr = true;
	if(!designatedScout || !designatedScout->exists())
	{
		designatedScout = 0;



		//if(vultures)
		//{
		//	for(std::list<BWAPI::Unit*>::iterator it = vultures->begin(); it != vultures->end(); it++)
		//	{
		//		if((*it)->getRemainingBuildTime()>0)
		//			continue;
		//		if((*it)->isIdle())
		//		{
		//			designatedScout = *it;
		//			break;
		//		}
		//		//if((*it)->isConstructing())
		//			//continue;
		//		//if((*it)->isGatheringMinerals())
		//			//designatedScout = *it;
		//	}

		//}
		//else
		//{
			for(std::list<BWAPI::Unit*>::iterator it = scvs->begin(); it != scvs->end(); it++)
			{
				if((*it)->getRemainingBuildTime()>0)
					continue;
				if((*it)->isIdle())
				{
					designatedScout = *it;
					break;
				}
				if((*it)->isConstructing())
					continue;
				if((*it)->isGatheringMinerals())
					designatedScout = *it;
			}
		//}
		if(designatedScout && designatedScout->isGatheringMinerals())
			designatedScout->stop();
	}
	if(designatedScout)
	{
		if(allPossibleBases.size() <= 0)
		{
			control->FinishWithFailure();
			return;
		}

		BWAPI::TilePosition target=allPossibleBases[currentBaseScouting], mine=BWAPI::TilePosition(designatedScout->getPosition());
		int diffX = target.x()-mine.x();
		int diffY = target.y()-mine.y();
		if(designatedScout->getTargetPosition() != BWAPI::Position(allPossibleBases[currentBaseScouting]))
		{
			designatedScout->move(BWAPI::Position(allPossibleBases[currentBaseScouting]));
		}
		if(diffX*diffX+diffY*diffY <= 4*4)
		{
			shouldIncr = true;
		}
		lastScoutFrame = BWAPI::Broodwar->getFrameCount();
		control->FinishWithSuccess();
	}
	else
	{
		control->FinishWithFailure();
	}

	if(shouldIncr && designatedScout && designatedScout->exists())
	{
		currentBaseScouting = (currentBaseScouting+1)%allPossibleBases.size();
		int limit = 18;
		while(!designatedScout->hasPath(BWAPI::Position(allPossibleBases[currentBaseScouting])) && limit>0)
		{
			currentBaseScouting = (currentBaseScouting+1)%allPossibleBases.size();
			limit--;
		}
	}
}

void Scout::Exit()
{
	DEBUG_PRINT("Exiting Scout behavior.\n");
}

bool Scout::CheckConditions()
{
	std::list<Base*>* bases = BB->GetBases();
	std::list<BWAPI::Unit*>* scvs = bases->front()->GetUnitsByType(BWAPI::UnitTypes::Terran_SCV);
	DEBUG_PRINT("CheckConditions Scout, found %d scvs\n", scvs->size());

	// only scout once we get some scvs to spare
	if(scvs->size() < 9)
		return false;

	return true;
	/*
	if(lastScoutFrame<0 || (BWAPI::Broodwar->getFrameCount() - lastScoutFrame >= ScoutingInterval))
		return true;
	
	return false;
	*/
}

void Scout::initPaths()
{
	allPossibleBases.clear();
	
	// Spawn locs
	BWAPI::TilePosition mainCCTilePos = BB->GetBases()->front()->GetBaseLocation();
	std::set<BWAPI::TilePosition> startLocs = BWAPI::Broodwar->getStartLocations();
	for(std::set<BWAPI::TilePosition>::iterator it=startLocs.begin();it!=startLocs.end();it++)
	{
		if((*it) != mainCCTilePos)
			allPossibleBases.push_back(*it);
	}

	// Expos
	std::list<BWAPI::TilePosition>* expos = BB->GetPossibleExpansions();
	std::list<BWAPI::TilePosition>::iterator start=expos->begin(), end=expos->end();
	while(start!=end)
	{
		allPossibleBases.push_back(*start);
		start++;
	}

	if(allPossibleBases.size() <= 0)
		isInitYet = false;
	else
		isInitYet = true;
}
